<template>
  <u-popup :show="show" @close="close" mode="right" bgColor="transparent">
    <view class="cu-dept-user-select-wrap">
      <view class="content-wrap">
        <view class="header">
          <view v-if="hasData" class="title">
            <scroll-view scroll-x style="width: 100%; white-space: nowrap" :scroll-left="scrollLeft">
              <view class="uni-inline-item">
                <view v-for="(item, index) in tree_stack" class="uni-inline-item" :key="index">
                  <view class="uni-inline-item" v-if="index == 0" @click="backTree(item, -1)">
                    <text :class="[isActive(index) && !showSearchResult ? 'none' : 'active']">根节点</text>
                  </view>
                  <view class="uni-inline-item" @click="backTree(item, index)" v-if="index != 0">
                    <u-icon name="arrow-right" size="12" color="#999999"></u-icon>
                    <view :class="isActive(index) ? 'none inline-ite' : 'active'"> {{ item[labelKey] }} </view>
                  </view>
                </view>
              </view>
            </scroll-view>
          </view>
          <u-gap bgColor="#F5F5F5" height="8" v-if="multiple"></u-gap>
        </view>
        <view style="flex: 1">
          <view
            class="select-all-wrap"
            @click="selectAllHandle"
            v-if="multiple && !disabledNodeLevel.includes(currentLevel)"
          >
            <SelectStatus :checked="selectAllStatus" />
            <view>全选当前页</view>
          </view>
          <u-gap bgColor="#F5F5F5" height="8"></u-gap>
          <scroll-view
            scroll-y="true"
            class="user-scroll-wrap"
            :style="{ height: safeArea.height - 40 - 54 - 60 - (multiple ? 58 : 0) + 'px' }"
          >
            <view class="container-list">
              <view
                class="common"
                :class="{
                  'is-disabled':
                    disabledNodeLevel.includes(currentLevel) && (!item[childrenKey] || !item[childrenKey].length)
                }"
                v-for="(item, index) in treeData"
                @click="handleNodeClick(item, index)"
                :key="item[valueKey]"
              >
                <label class="info-content">
                  <view class="uni-inline-item">
                    <view
                      v-if="!disabledNodeLevel.includes(currentLevel)"
                      class="select-icon-wrap"
                      @click.stop="handleNodeClick(item, -1)"
                    >
                      <SelectStatus :checked="isNodeSelect(item)" />
                    </view>
                    <view class="dept-icon-wrap">
                      <image class="dept-icon" src="./image/default_dept_icon.png" mode="aspectFit"> </image>
                    </view>
                    <view class="dept-name"> {{ item[labelKey] }}</view>
                  </view>
                  <view class="uni-inline-item">
                    <u-icon
                      name="arrow-right"
                      v-if="item[childrenKey] && item[childrenKey].length"
                      size="12"
                      color="#999999"
                    ></u-icon>
                  </view>
                </label>
              </view>
            </view>
          </scroll-view>
        </view>
        <view class="btn box_sizing">
          <view class="bottom-btn-wrap" v-if="multiple" @click="selectedInfoPopup = true">
            <template v-if="nodeCheckList.length > 0">
              <view class="selected-text"> 已选择：{{ nodeCheckLabel }} </view>
            </template>
            <view class="selected-text" v-else>未选择</view>
            <u-icon class="arrow-up" name="arrow-up" size="12" color="#2c7be7"></u-icon>
            <button class="confirm-btn" type="primary" @click.stop="backConfirm">
              <text>确定</text>
            </button>
          </view>

          <!-- 单选底部信息 -->
          <view class="bottom-btn-wrap" v-else>
            <template v-if="nodeCheckList.length > 0">
              <view class="selected-text u-line-1"> 已选择：{{ nodeCheckList[0][labelKey] }} </view>
            </template>
            <view class="selected-text" v-else>未选择</view>
            <button class="confirm-btn" type="primary" @click.stop="backConfirm">确定</button>
          </view>
        </view>
      </view>
      <u-popup :show="selectedInfoPopup" mode="bottom" @close="selectedInfoPopup = false" round="10">
        <view class="selected-inof-popup-wrap">
          <view class="uni-inline-item popup-header">
            <view class="selected-text u-line-1"> 已选择：{{ nodeCheckList.length }}</view>
            <view class="close-popup-btn" @click="selectedInfoPopup = false">关闭</view>
          </view>
          <scroll-view scroll-y="true" class="user-scroll-wrap">
            <template>
              <view
                class="common"
                v-for="item in nodeCheckList"
                @click="handleNodeClick(item, -1)"
                :key="item[valueKey]"
              >
                <label class="info-content">
                  <view class="uni-inline-item">
                    <!-- 多选 -->
                    <view class="select-icon-wrap">
                      <SelectStatus :checked="isNodeSelect(item)" />
                    </view>
                    <view class="dept-icon-wrap">
                      <image class="dept-icon" src="./image/default_dept_icon.png" mode="aspectFit"> </image>
                    </view>
                    <view class="dept-name u-line-1"> {{ item[labelKey] }}</view>
                  </view>
                  <view class="uni-inline-item" v-if="item[childrenKey]"> </view>
                </label>
              </view>
            </template>
            <u-gap bgColor="#F5F5F5" height="8"></u-gap>
          </scroll-view>
        </view>
      </u-popup>
    </view>
  </u-popup>
</template>

<script>
import { staticUrl } from '@/config.js'
import Search from './components/Search.vue'
import SelectStatus from './components/SelectStatus.vue'

export default {
  props: {
    checkList: {
      type: [Number, String, Array]
    },
    multiple: {
      type: Boolean,
      default: false
    },
    rootNodeId: {
      type: [String, Number],
      default: ''
    },
    disabledNodeLevel: {
      type: Array,
      default: () => []
    },
    labelKey: {
      type: String,
      default: 'label'
    },
    valueKey: {
      type: String,
      default: 'value'
    },
    childrenKey: {
      type: String,
      default: 'children'
    },
    requestApi: {
      type: Function
    }
  },
  data() {
    return {
      hasData: false,
      keyword: '',
      staticUrl: staticUrl,
      showSearchResult: false, // 是否搜索1
      treeData: [], // 部门数据
      catchTreeNone: [],
      tree_stack: ['通讯录'],
      searchResult: [],
      nodeCheckList: [],
      scrollLeft: 999,
      selectedInfoPopup: false, // 已选择人员信息
      show: false,
      safeArea: { height: 0 }
    }
  },
  components: {
    Search,
    SelectStatus
  },
  computed: {
    currentLevel() {
      return this.tree_stack.length
    },
    selectAllStatus() {
      if (this.treeData.length === 0) return false
      return this.treeData.every((i) => {
        return this.nodeCheckList.some((j) => j[this.valueKey] === i[this.valueKey])
      })
    },
    // 部门是否选中
    isNodeSelect() {
      return (item) => {
        const index =
          this.nodeCheckList.findIndex((e) => {
            return item[this.valueKey] === e[this.valueKey]
          }) > -1
        return index
      }
    },
    isActive() {
      return (index) => {
        return index === this.tree_stack.length - 1
      }
    },
    nodeCheckLabel() {
      if (!this.nodeCheckList?.length) {
        return ''
      }
      if (this.nodeCheckList.length === 1) {
        return this.nodeCheckList[0][this.labelKey]
      }
      return this.nodeCheckList[0][this.labelKey] + `...等${this.nodeCheckList.length}条数据`
    }
  },
  mounted() {
    uni.getSystemInfo({
      success: (res) => {
        this.safeArea = res.safeArea
      },
      fail: (err) => {
        reject(err)
      }
    })
  },
  methods: {
    reset() {
      this.nodeCheckList = []
      this.backTree('通讯录', -1)
      uni.hideLoading()
    },
    open() {
      this.keyword = ''
      this.$nextTick(() => {
        if (!Array.isArray(this.checkList)) {
          this.nodeCheckList = []
        } else {
          this.nodeCheckList = JSON.parse(JSON.stringify(this.checkList))
        }
        this.Init()
        this.show = true
      })
    },
    close() {
      this.show = false
      this.$emit('close')
      this.reset()
    },
    selectAllHandle() {
      if (this.selectAllStatus) {
        // 反选
        this.nodeCheckList = this.deleteArr(this.nodeCheckList, this.treeData, this.valueKey)
      } else {
        // 全选
        this.nodeCheckList = this.combineArr(this.treeData, this.nodeCheckList, this.valueKey)
      }
    },
    // 数组合并去重 （全选）
    combineArr(arr1, arr2, key) {
      const arrs = [...arr1, ...arr2]
      // 根据key去重
      const map = new Map()
      for (const item of arrs) {
        if (!map.has(item[key])) {
          map.set(item[key], item)
        }
      }
      return [...map.values()]
    },
    // 数组合并删除 (反选)
    deleteArr(arr1, arr2, key) {
      const arrs = [...arr1, ...arr2]
      // 根据key去重
      const map = new Map()
      for (const item of arrs) {
        if (map.has(item[key])) {
          map.delete(item[key])
        } else {
          map.set(item[key], item)
        }
      }
      return [...map.values()]
    },
    // 初始化
    async Init() {
      await this.getData()
    },
    async getData() {
      if (!this.requestApi) {
        return
      }
      const res = await this.requestApi()
      res.data = res.data || res.rows
      this.hasData = res.data.length > 0
      this.treeData = res.data
      if (this.rootNodeId) {
        this.treeData = this.filterNodeTree(res.data, this.rootNodeId)
      }
      this.catchTreeNone = this.treeData
    },
    filterNodeTree(originData, nodeId) {
      let result = []
      const that = this
      function recursiveFilter(items) {
        items.forEach((item) => {
          if (item[that.valueKey] === nodeId) {
            result.push(item)
          } else if (item[that.childrenKey]) {
            recursiveFilter(item[that.childrenKey])
          }
        })
      }

      recursiveFilter(originData)

      return result
    },
    // 部门点击处理
    async handleNodeClick(item, index) {
      if (index > -1) {
        if (item[this.childrenKey]?.length) {
          this.toChildren(item)
        } else {
          this.choose(item, index)
        }
      } else {
        this.choose(item, index)
      }
    },
    choose(item, index) {
      if (this.disabledNodeLevel.includes(this.currentLevel)) {
        this.$modal.showToast('当前层级不允许选择')
        return
      }
      if (this.multiple) {
        this.nodeMultipleClick(item, index)
      } else {
        this.nodeRadioClick(item)
      }
    },
    // 节点单选
    nodeRadioClick(item) {
      this.$set(this, 'nodeCheckList', [
        {
          ...item
        }
      ])
    },
    // 节点多选
    nodeMultipleClick(item) {
      const findIndex = this.nodeCheckList.findIndex((e) => item[this.valueKey] === e[this.valueKey])
      if (findIndex > -1) {
        this.nodeCheckList.splice(findIndex, 1)
      } else {
        this.nodeCheckList.push(item)
      }
    },

    // 到下一级
    toChildren(item) {
      this.treeData = item[this.childrenKey]
      this.tree_stack.push(item)
      this.$nextTick(() => {
        this.scrollLeft += 200
      })
    },

    // 返回其它层
    async backTree(item, index) {
      const max = 300
      if (index === -1) {
        // 返回根节点顶层
        this.treeData = this.catchTreeNone
        this.tree_stack.splice(1, max)
        this.showSearchResult = false
      } else {
        this.tree_stack.splice(index + 1, max)
        this.treeData = item[this.childrenKey]
      }
    },
    async backConfirm() {
      const nodeList = []
      this.nodeCheckList.forEach((item) => {
        nodeList.push({
          ...item
        })
      })
      this.$emit('change', JSON.parse(JSON.stringify(nodeList)))
      this.close()
    }
  }
}
</script>
<style lang="scss" scoped>
@import './css/style.scss';
</style>
